/*
 * Copyright (c) 2013 - 2014, Freescale Semiconductor, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * o Redistributions of source code must retain the above copyright notice, this list
 *   of conditions and the following disclaimer.
 *
 * o Redistributions in binary form must reproduce the above copyright notice, this
 *   list of conditions and the following disclaimer in the documentation and/or
 *   other materials provided with the distribution.
 *
 * o Neither the name of Freescale Semiconductor, Inc. nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "server_common.h"
#include "server_thread.h"

/* Initialization */
bool initServer(void);
bool initSocket(void);
bool initKABSLog(void);
/* Server configure struct */
ServerConfigure g_serverConfig = {"server_config.ini",     /* Configure file name */
                                  "kabs_log.ini",          /* KABS log information */
                                  false,                  /* Initial accept state */
                                  0,                   /* Ports and heartbeat default information */
                                  0,
                                  0,
                                  120};

/* Thread ID, these are created for extending demand */
DWORD g_acceptRegThreadID;
DWORD g_acceptHBThreadID;
DWORD g_acceptRQThreadID;
DWORD g_messageProcThreadID;

int main(void)
{
    bool result1 = initServer();
    bool result2 = initSocket();
    bool result3 = initKABSLog();

    if (result1 && result2 && result3)
    {
        // open screen show
        g_default_log.setMode(false);
        g_register_log.setMode(false);
        g_heartbeat_log.setMode(false);
        g_request_log.setMode(false);
        g_default_log << tstamp << "Initialize successfully.\n";
        g_default_log << tstamp << "Registration Port: "<<g_serverConfig.portRegister<<",\n";
        g_default_log << tstamp << "Heartbeat Port: "<<g_serverConfig.portHeartbeat<<",\n";
        g_default_log << tstamp << "Request Port: "<<g_serverConfig.portRequest<<",\n";
        g_default_log << tstamp << "Heartbeat timeout: "<<g_serverConfig.timeout<<" seconds.\n";

        /* Create thread for registration */
        CreateThread(NULL, 0, \
                     (LPTHREAD_START_ROUTINE)svr::accept::acceptRegister, \
                     (void *)NULL, 0, &g_acceptRegThreadID);
        /* Create thread for heartbeat */
        CreateThread(NULL, 0, \
                    (LPTHREAD_START_ROUTINE)svr::accept::acceptHeartbeat, \
                    (void *)NULL, 0, &g_acceptHBThreadID);
        /* Create thread for request */
        CreateThread(NULL, 0, \
                    (LPTHREAD_START_ROUTINE)svr::accept::acceptRequest, \
                    (void *)NULL, 0, &g_acceptRQThreadID);
        /* Create thread for timer message */
        HANDLE message_proc_handle = CreateThread(NULL, 0, \
                                             (LPTHREAD_START_ROUTINE)svr::message::messageProc, \
                                             (void *)NULL, 0, &g_messageProcThreadID);

        /* Hold main thread, otherwise whole process will be killed */
        WaitForSingleObject(message_proc_handle, INFINITE);
    }
    else
    {
        dispTime();
        printf("Initial Failed, please set config file correctly and restart.\n");

        g_default_log << tstamp << "Initial Failed, please set config file correctly and restart.\n";
    }

    dispTime();
    printf("Some fatal error happens, please check log.\n");
    system("pause");

    return 0;
}

/*FUNCTION*********************************************************************
 *
 * Function Name : initServer
 * Description   : Configure server according to .ini file. The .ini file's
 * name is defined in global struct variable g_serverConfig. This function
 * read ports information used for create listening sockets and heartbeat
 * period as well. As port 0 is NOT supposed to be used in this application,
 * reading any 0 port will cause this initialization fails.
 *END*************************************************************************/
bool initServer(void)
{
    char full_path[256];
    sprintf(full_path, ".\\%s", g_serverConfig.configFileName);
    /* Set configure information */
    g_serverConfig.portRegister = ::GetPrivateProfileIntA("TCPIP", "port_register", 0, full_path);
    g_serverConfig.portHeartbeat = ::GetPrivateProfileIntA("TCPIP", "port_heartbeat", 0, full_path);
    g_serverConfig.portRequest = ::GetPrivateProfileIntA("TCPIP", "port_request", 0, full_path);
    g_serverConfig.timeout = ::GetPrivateProfileIntA("TCPIP", "timeout", 120, full_path);
    if (g_serverConfig.portRegister == 0 ||
        g_serverConfig.portHeartbeat == 0 ||
        g_serverConfig.portRequest == 0)
        return false;
    /* Enable accept clients */
    g_serverConfig.enableAccept = true;
    return true;
}

/*FUNCTION*********************************************************************
 *
 * Function Name : initSocket
 * Description   : Initiates use of the wsock32.dll.
 *END*************************************************************************/
bool initSocket(void)
{
    WSADATA wsa_data;

    uint32_t i_result = WSAStartup(MAKEWORD(2, 2), &wsa_data);
    if (i_result != NO_ERROR)
    {
        dispTime();
        printf("WSAStartup failed: %d\n", i_result);

        g_default_log << tstamp << "WSAStartup failed: "<<i_result<<"\n";

        return false;
    }
    return true;
}

/*FUNCTION*********************************************************************
 *
 * Function Name : initKABSLog
 * Description   : Set all existing KABS to be offline.
 *END*************************************************************************/
bool initKABSLog(void)
{
    char full_path[256];
    char *uids = new char[MAXUID * (UIDLEN + 1)];
    uint32_t last = 0;

    /* Set all character to '\0' */
    memset(uids, 0, MAXUID * (UIDLEN + 1));
    /* Get all UIDs for reset */
    sprintf(full_path, ".\\%s", g_serverConfig.logFileName);
    ::GetPrivateProfileSectionNamesA(uids, MAXUID * (UIDLEN + 1), full_path);
    /* Iterate all UIDs and reset their state */
    for (uint32_t i = 0; i < MAXUID * (UIDLEN + 1); i++)
    {
        if (uids[i] != '\0') continue;
        else
        {
            if (i - last == UIDLEN) /* Valid UID */
            {
                char *uid_p = uids + last;
                ::WritePrivateProfileStringA(uid_p, "STATE", "0", full_path);
                last = i + 1;
            }
            else break;
        }
    }

    delete uids;

    return true;
}


/*EOF*/
